package com.example.nick.bodyapplication.widget

import android.content.Context
import android.content.res.Resources
import android.graphics.Canvas
import android.graphics.Color
import android.graphics.Paint
import android.graphics.RectF
import android.util.AttributeSet
import android.util.Log
import android.view.MotionEvent
import android.view.View
import android.widget.ScrollView
import android.widget.Toast
import com.example.nick.bodyapplication.R
import kotlin.math.ceil

class WeekDayTabView2 : View {

    val _dayCount = 7
    val _hourCount = 24

    var weekDayArr = Array(size = _dayCount, init = { Array(_hourCount, init = { 0 }) })
    val dayHoursArr = Array(size = _hourCount, init = { 0 })

    private var itemWidth = 0.0f
    private var itemHeight = 0.0f
    private val itemHeightScalc = 0.60f

    /**
     * 最左边时间line width 为 item * 0.57
     * Time line width
     */
    private val timeLineScalc = 0.5747f
    private var timeLineWidth = 0.0f
    private var timeLineHeight = 0.0f

    private var weekHeight = 0.0f

    private var paintLine = Paint(Paint.ANTI_ALIAS_FLAG)
    private var paintTime = Paint(Paint.ANTI_ALIAS_FLAG)
    private var paintTextWeek = Paint(Paint.ANTI_ALIAS_FLAG)
    private var paintRect = Paint(Paint.ANTI_ALIAS_FLAG)

    private val spaceSize = 7
    private val spaceSizeY = 7

    private var curRow = 0
    private var curColumn = 0
    private var moveRow = 0
    private var moveColumn = 0

    var scrollView: ScrollView? = null

    var horColor = Color.RED
    var pspColor = Color.BLUE
    var disColor = Color.GRAY
    var txtColor = Color.BLACK
    var ptzMode = true
    var autoHeightMode = false
    var touchRectMode = false
    var toastUtc = 0L
    /**
     * 当前触摸的单元格 是 on / off，例如是on则modeOn为false表示取消
     * Model on
     */
    var modelOn = true

    /**
     * 0b00， 0b01, 0b10, 0b11
     * Cruise flag, 0表示 hor / psp都是关闭， 1 表示 hor 开启， 2 表示 psp开启， 3 表示 hor / psp 都开启
     */
    var cruiseFlag = 0b00
    val cruiseValueHor = 0b01
    val cruiseValuePsp = 0b10
    var horClickEnable = true
    var dataHasChange = false

    var downTime = 0L

    constructor(ctx: Context) : super(ctx, null)
    constructor(ctx: Context, attrs: AttributeSet) : this(ctx, attrs, 0)
    constructor(ctx: Context, attrs: AttributeSet, defStyleAttr: Int) : super(
        ctx,
        attrs,
        defStyleAttr
    ) {
        initAttrs(ctx, attrs)
    }

    private fun initAttrs(ctx: Context, attrs: AttributeSet) {
        val typedArray = context.obtainStyledAttributes(attrs, R.styleable.WeekDayTabView)
        //获取自定义属性和默认值
        horColor = typedArray.getColor(R.styleable.WeekDayTabView_horColor, Color.RED)
        pspColor = typedArray.getColor(R.styleable.WeekDayTabView_pspColor, Color.BLUE)
        disColor = typedArray.getColor(R.styleable.WeekDayTabView_disColor, Color.GRAY)
        txtColor = typedArray.getColor(R.styleable.WeekDayTabView_txtColor, Color.BLACK)
        ptzMode = typedArray.getBoolean(R.styleable.WeekDayTabView_ptzMode, true)
        autoHeightMode = typedArray.getBoolean(R.styleable.WeekDayTabView_autoHeightMode, false)
        touchRectMode = typedArray.getBoolean(R.styleable.WeekDayTabView_touchRectMode, false)
        typedArray.recycle()
        paintLine.color = resources.getColor(R.color.newDividerColor)
        paintLine.strokeWidth = dp2px(1f).toFloat()
        paintTime.color = txtColor
        paintTime.textSize = dp2px(9.33f).toFloat()
        paintTextWeek.color = resources.getColor(R.color.newMainTextColor)
        paintTextWeek.textSize = dp2px(12f).toFloat()
        paintTextWeek.style = Paint.Style.FILL
        paintTextWeek.textAlign = Paint.Align.CENTER
        dataHasChange = false
    }

    override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec)
        val v_w = measureWidth(widthMeasureSpec)
        val v_height = measureWidth(heightMeasureSpec)
        itemWidth = (v_w - 2 * spaceSize) / (_dayCount + timeLineScalc)
        timeLineWidth = itemWidth * timeLineScalc
        timeLineHeight = timeLineWidth * 0.7123f
        if (autoHeightMode) {
            itemHeight = (v_height - 2 * spaceSize) / (_hourCount + 1.4588f)
            weekHeight = itemHeight * 1.4588f
            setMeasuredDimension(v_w, ceil(v_height.toDouble()).toInt())
        } else {
            itemHeight = itemWidth * itemHeightScalc
            weekHeight = itemHeight * 1.4588f
            var v_h = weekHeight + itemHeight * _hourCount + 2 * spaceSize
            setMeasuredDimension(v_w, ceil(v_h.toDouble()).toInt())
        }
    }

    private fun measureWidth(measureSpec: Int): Int {
        val specMode = MeasureSpec.getMode(measureSpec)
        val specSize = MeasureSpec.getSize(measureSpec)
        //设置一个默认值，就是这个View的默认宽度为500，这个看我们自定义View的要求
        var result = 500
        if (specMode == MeasureSpec.AT_MOST) {//相当于我们设置为wrap_content
            result = specSize
        } else if (specMode == MeasureSpec.EXACTLY) {//相当于我们设置为match_parent或者为一个具体的值
            result = specSize
        } else {
            result = specSize
        }
        Log.i(
            "v_t",
            "v_t measureWidth AT_MOST:${MeasureSpec.AT_MOST}, EXACTLY:${MeasureSpec.EXACTLY}, UNSPECIFIED:${MeasureSpec.UNSPECIFIED}"
        )
        Log.i("v_t", "v_t measureWidth specMode:$specMode, specSize:$specSize, result:$result")
        return result
    }

    override fun onDraw(canvas: Canvas) {
//        itemWidth = width.toFloat() / (7 + timeLineScalc)
//        itemHeight = itemWidth * itemHeightScalc
//        timeLineWidth = itemWidth * timeLineScalc
//        timeLineHeight = timeLineWidth * 0.7123f
//        weekHeight = itemHeight * 1.4588f

        canvas.save()
        drawWeekTop(canvas)
        drawDay(canvas)
        drawRectLine(canvas)
        drawTimeLine(canvas)
        canvas.restore()
    }

    private fun drawRectLine(canvas: Canvas) {
        // 绘制竖线
//        Log.i("v_t", "v_t width:$width, height:$height")
        val rowXStart = timeLineWidth + spaceSize
        val rowXEnd = width.toFloat() - spaceSize
        val columnYStart = spaceSize.toFloat() + weekHeight
        val columnYEnd = height.toFloat() - spaceSize
        for (i in 0.._dayCount) {
            var lineX = rowXStart + i * itemWidth
//            Log.d(
//                "v_t",
//                "v_t lineX:$lineX, timeLineWidth:$timeLineWidth, itemWidth:$itemWidth, itemHeith:$itemHeight"
//            )
            canvas.drawLine(
                lineX,
                columnYStart,
                lineX,
                columnYEnd,
                paintLine
            )
        }

        // 绘制横线
//        canvas.drawLine(rowXStart, spaceSize.toFloat(), rowXEnd, spaceSize.toFloat(), paintLine)
        for (i in 0.._hourCount) {
            var lineY = weekHeight + i * itemHeight + spaceSize
//            Log.i(
//                "v_t",
//                "v_t lineY:$lineY, timeLineWidth:$timeLineWidth, itemWidth:$itemWidth, itemHeith:$itemHeight"
//            )
            canvas.drawLine(
                rowXStart,
                lineY,
                rowXEnd,
                lineY,
                paintLine
            )
        }
    }

    private fun drawDay(canvas: Canvas) {
        val rowXStart = timeLineWidth + spaceSize
        val columnYStart = weekHeight + spaceSize.toFloat()

        weekDayArr.forEachIndexed { i, day ->
            day.forEachIndexed { j, hour ->
                when (hour) {
                    1 -> paintRect.color =
                        if (cruiseFlag and cruiseValueHor == cruiseValueHor) horColor else disColor
                    2 -> paintRect.color =
                        if (cruiseFlag and cruiseValuePsp == cruiseValuePsp) pspColor else disColor
                    //3 -> paintRect.color = disColor
                    else -> paintRect.color = Color.WHITE
                }
                canvas.drawRect(
                    rowXStart + i * itemWidth,
                    columnYStart + j * itemHeight,
                    rowXStart + (i + 1) * itemWidth,
                    columnYStart + (j + 1) * itemHeight,
                    paintRect
                )
            }
        }
    }

    private fun drawTimeLine(canvas: Canvas) {
        var textHeight = dp2px(9.33f)
        for (i in 0.._hourCount) {
            canvas.drawText(
                "$i:00",
                spaceSize.toFloat(),
                weekHeight + i * itemHeight + textHeight / 2,
                paintTime
            )
        }
    }

    private fun drawWeekTop(canvas: Canvas) {
        paintTextWeek.textSize = dp2px(12f).toFloat()
        val rowXStart = timeLineWidth + spaceSize
        val columnYStart = spaceSize.toFloat()
        for (i in 0..6) {
            //矩形背景
            val bgRect = Paint()
            bgRect.style = Paint.Style.FILL
            bgRect.color = Color.TRANSPARENT
            val rectF = RectF(
                rowXStart + i * itemWidth,
                columnYStart,
                rowXStart + (i + 1) * itemWidth,
                columnYStart + weekHeight
            )
            canvas.drawRect(rectF, bgRect)
            val text = getWeekStr(i)
            //计算baseline
            val fontMetrics = paintTextWeek.fontMetrics
            val distance = (fontMetrics.bottom - fontMetrics.top) / 2 - fontMetrics.bottom
            val baseline = rectF.centerY() + distance
            canvas.drawText(text, rectF.centerX(), baseline, paintTextWeek)
        }
    }

    fun getWeekStr(i: Int): String {
        var day = ""
        when (i) {
            0 -> day = "周0"
            1 -> day = "周1"
            2 -> day = "周2"
            3 -> day = "周3"
            4 -> day = "周4"
            5 -> day = "周5"
            6 -> day = "周6"
        }
        return day
    }

    fun updateArrays(arr: Array<Array<Int>>) {
        weekDayArr = arr
        invalidate()
    }

    fun updateFlag(flag: Int) {
        cruiseFlag = flag
        invalidate()
    }

    override fun onTouchEvent(event: MotionEvent): Boolean {
        when (event.action) {
            MotionEvent.ACTION_DOWN -> {
                if (touchRectMode) {
                    val (r, c) = getRowColumn(event.x, event.y)
                    if (r < 0 || c < 0) {
                        return true
                    }
                    curRow = r
                    curColumn = c

                    modelOn = weekDayArr[c][r] != 1

                    if (judgeOneDay4(r, c)) {
                        weekDayArr[c][r] = if (modelOn) 1 else 0
                        dataHasChange = true
                        invalidate()
                    } else {
                        toast4or6(true)
                    }
                    Log.i(
                        "v_t",
                        "v_t down x:${event.x}, y:${event.y}, r:$r, c:$c, modelOn:$modelOn"
                    )
                } else {
                    downTime = System.currentTimeMillis()
                    val (r, c) = getRowColumn(event.x, event.y)
                    Log.d(
                        "v_t",
                        "v_t down x:${event.x}, y:${event.y}, r:$r, c:$c, downTime:$downTime}"
                    )
                    //scrollView?.requestDisallowInterceptTouchEvent(true)
                }
            }
            MotionEvent.ACTION_MOVE -> {
                if (touchRectMode) {
                    val (r, c) = getRowColumn(event.x, event.y)
                    if (r < 0 || c < 0) {
                        return true
                    }
                    Log.d(
                        "v_t",
                        "v_t move r:$r, c:$c, modelOn:$modelOn, r:$r, c:$c, curRow:$curRow, curColumn:$curColumn"
                    )
                    if (curRow != r || curColumn != c) {
                        dealTouchMove(r, c)
                    }
                } else {
                    if (autoHeightMode) {
                        val (r, c) = getRowColumn(event.x, event.y)
                        Log.d(
                            "v_t",
                            "v_t move x:${event.x}, y:${event.y}, r:$r, c:$c, curRow:$curRow, curColumn:$curColumn, downTime:$downTime, ptzMode:$ptzMode"
                        )
                        if (r == -1 || c == -1) {
                            return true
                        }

                        if (ptzMode) {
                            if (horClickEnable && weekDayArr[c][r] == cruiseValuePsp) {
                                return true
                            }
                            if (!horClickEnable && weekDayArr[c][r] == cruiseValueHor) {
                                return true
                            }
                            curRow = r
                            curColumn = c
                            Log.i(
                                "v_t",
                                "v_t move x:${event.x}, y:${event.y}, r:$r, c:$c, scrollY:${scrollView?.scrollY}, scrollView.h:${scrollView?.height}"
                            )
                            if (dealItemCheck(r, c)) {
                                dataHasChange = true
                                invalidate()
                            } else {
                                if (System.currentTimeMillis() - toastUtc > 2000) {
                                    toastUtc = System.currentTimeMillis()
                                    Toast.makeText(context, "不能超过6小时", Toast.LENGTH_SHORT).show()
                                }
                            }
                        } else {
                            Log.i(
                                "v_t",
                                "v_t move r:$r, c:$c, curRow:$curRow, curColumn:$curColumn"
                            )
                            if (curRow != r || curColumn != c) {
                                curRow = r
                                curColumn = c
                                if (dealOneDay4(r, c)) {
                                    Log.e(
                                        "v_t",
                                        "v_t move x:${event.x}, y:${event.y}, dealOneDay4 ok"
                                    )
                                    dataHasChange = true
                                    invalidate()
                                } else {
                                    Log.e(
                                        "v_t",
                                        "v_t move x:${event.x}, y:${event.y}, Toast ok"
                                    )
                                    if (System.currentTimeMillis() - toastUtc > 2000) {
                                        Log.e(
                                            "v_t",
                                            "v_t move x:${event.x}, y:${event.y}, Toast 2000"
                                        )
                                        toastUtc = System.currentTimeMillis()
                                        Toast.makeText(context, "不能设置4个时间段", Toast.LENGTH_SHORT).show()
                                    }
                                }
                            }
                        }
                    }
                }
            }
            MotionEvent.ACTION_UP -> {
                Log.d(
                    "v_t",
                    "v_t up x:${event.x}, y:${event.y}, curRow:$curRow, curColumn:$curColumn, downTime:$downTime, System.currentTimeMillis():${System.currentTimeMillis()}"
                )
                if (touchRectMode) {

                } else {

                    // 触摸超过200ms就认为是长按
                    if (System.currentTimeMillis() - downTime > 200) {
                        return true
                    }
                    val (r, c) = getRowColumn(event.x, event.y)
                    if (r == -1 || c == -1) {
                        return true
                    }

                    if (ptzMode) {
                        if (horClickEnable && weekDayArr[c][r] == cruiseValuePsp) {
                            return true
                        }
                        if (!horClickEnable && weekDayArr[c][r] == cruiseValueHor) {
                            return true
                        }
                        curRow = r
                        curColumn = c
                        Log.i(
                            "v_t",
                            "v_t down x:${event.x}, y:${event.y}, r:$r, c:$c, scrollY:${scrollView?.scrollY}, scrollView.h:${scrollView?.height}"
                        )
                        if (dealItemCheck(r, c)) {
                            dataHasChange = true
                            invalidate()
                        } else {
                            if (System.currentTimeMillis() - toastUtc > 2000) {
                                toastUtc = System.currentTimeMillis()
                                Toast.makeText(context, "不能超过6小时", Toast.LENGTH_SHORT).show()
                            }
                        }
                    } else {
                        curRow = r
                        curColumn = c
                        if (dealOneDay4(r, c)) {
                            dataHasChange = true
                            invalidate()
                        } else {
                            if (System.currentTimeMillis() - toastUtc > 2000) {
                                toastUtc = System.currentTimeMillis()
                                Toast.makeText(context, "不能设置4个时间段", Toast.LENGTH_SHORT).show()
                            }
                        }
                    }
                }
            }
        }
        return true
    }

    fun dealTouchMove(moveR: Int, moveC: Int) {
        var beginRow = 0
        var beginColumn = 0
        var endRow = 0
        var endColumn = 0
        if (moveR > curRow) {
            beginRow = curRow
            endRow = moveR
        } else {
            beginRow = moveR
            endRow = curRow
        }

        if (moveC > curColumn) {
            beginColumn = curColumn
            endColumn = moveC
        } else {
            beginColumn = moveC
            endColumn = curColumn
        }

        for (index in 0 until _dayCount * _hourCount) {
            val c = index / _hourCount
            val r = index % _hourCount
            Log.d(
                "v_t",
                "v_t dealTouchMove for r:$r, c:$c, modelOn:$modelOn"
            )
            if (r in beginRow..endRow && c in beginColumn..endColumn) {
                Log.i(
                    "v_t",
                    "v_t dealTouchMove r:$r, c:$c, modelOn:$modelOn, beginRow:$beginRow, endRow:$endRow, beginColumn:$beginColumn, endColumn:$endColumn"
                )
                if (judgeOneDay4(r, c)) {
                    weekDayArr[c][r] = if (modelOn) 1 else 0
                    dataHasChange = true
                    invalidate()
                } else {
                    toast4or6(true)
                }
            }
        }
        invalidate()
    }

    private fun toast4or6(four: Boolean) {
        if (System.currentTimeMillis() - toastUtc < 2000) {
            return
        }
        toastUtc = System.currentTimeMillis()
        if (four) {
            Toast.makeText(context, "4个连续时段", Toast.LENGTH_SHORT).show()
        } else {
            Toast.makeText(context, "连续6小时", Toast.LENGTH_SHORT).show()
        }
    }

    private fun judgeOneDay4(r: Int, c: Int): Boolean {
        for (i in 0..23) {
            dayHoursArr[i] = weekDayArr[c][i]
        }
        dayHoursArr[r] = if (modelOn) 1 else 0
        var count = 0
        var index = -2
        for (i in 0..23) {
            val v = dayHoursArr[i]
            if (v == cruiseValueHor) {
                if (i - index > 1) {
                    count++
                }
                index = i
            }
        }
        Log.i(
            "v_t",
            "v_t count:$count, index:$index"
        )
        if (count > 4) {
            return false
        }
        return true
    }

    private fun dealOneDay4(r: Int, c: Int): Boolean {
        // 计算选中模块
        for (i in 0..23) {
            dayHoursArr[i] = weekDayArr[c][i]
        }
        dayHoursArr[r] = if (dayHoursArr[r] == cruiseValueHor) 0 else cruiseValueHor
        var count = 0
        var index = -2
        for (i in 0..23) {
            val v = dayHoursArr[i]
            if (v == cruiseValueHor) {
                if (i - index > 1) {
                    count++
                }
                index = i
            }
        }
        Log.i(
            "v_t",
            "v_t count:$count, index:$index"
        )
        if (count > 4) {
            return false
        }
        weekDayArr[c][r] = dayHoursArr[r]
        return true
    }

    /**
     * 不能连续6个小时
     * @param r Int
     * @param c Int
     * @return Boolean
     */
    private fun dealItemCheck(r: Int, c: Int): Boolean {
        if (weekDayArr[c][r] != 0) {
            weekDayArr[c][r] = 0
            return true
        }

        var count = _hourCount
        var left = r - 1
        var right = r + 1
        var canLeft = true
        var canRight = true
        var sum = 0
        var changeCRight = c
        var changeCLeft = c
        while (--count > 0) {
            if (canRight) {// 向后计算
                if (changeCRight in 0 until _dayCount) {
                    if (right <= _hourCount - 1) {
                        if (weekDayArr[changeCRight][right] == 0) {
                            canRight = false
                        } else {
                            sum += 1
                        }
                        Log.i(
                            "v_t",
                            "v_t weekDayArr[$changeCRight][$right]:${weekDayArr[changeCRight][right]}, canRight:$canRight, sum:$sum"
                        )
                        right += 1
                    } else if (changeCRight == c && right == _hourCount) { // 跨天处理
                        changeCRight = if (c == 6) 0 else c + 1 // 周7与周6，列的切换
                        right = 0
                        if (weekDayArr[changeCRight][right] == 0) {
                            canRight = false
                        } else {
                            sum += 1
                            right += 1
                        }
                        Log.i(
                            "v_t",
                            "v_t other weekDayArr[$changeCRight][$right]:${weekDayArr[changeCRight][right]}, canRight:$canRight, sum:$sum"
                        )
                    }
                }
            }

            if (canLeft) {// 向前计算
                if (changeCLeft in 0 until _dayCount) {
                    if (left >= 0) {
                        if (weekDayArr[changeCLeft][left] == 0) {
                            canLeft = false
                        } else {
                            sum += 1
                        }
                        Log.i(
                            "v_t",
                            "v_t weekDayArr[$changeCLeft][$left]:${weekDayArr[changeCLeft][left]}, canLeft:$canLeft, sum:$sum"
                        )
                        left -= 1
                    } else if (changeCLeft == c && left == -1) { // 跨天处理
                        changeCLeft = if (c == 0) 6 else c - 1 // 周6与周7，列的切换
                        left = _hourCount - 1
                        if (weekDayArr[changeCLeft][left] == 0) {
                            canLeft = false
                        } else {
                            sum += 1
                            left -= 1
                        }
                        Log.i(
                            "v_t",
                            "v_t other weekDayArr[$changeCLeft][$left]:${weekDayArr[changeCLeft][left]}, canLeft:$canLeft, sum:$sum"
                        )
                    }
                }
            }

            Log.i(
                "v_t",
                "v_t count:$count, sum:$sum, canRight:$canRight, canLeft:$canLeft"
            )

            if (!canRight && !canLeft) {
                break
            }

            if (sum >= 6) { // 不能连续6个小时
                return false
            }
        }
        weekDayArr[c][r] = if (horClickEnable) cruiseValueHor else cruiseValuePsp
        return true
    }

    fun getRowColumn(touchX: Float, touchY: Float): Pair<Int, Int> {
        val rowXStart = timeLineWidth + spaceSize
        val columnYStart = weekHeight + spaceSize.toFloat()

        var r = ((touchY - columnYStart) / itemHeight).toInt()
        var c = ((touchX - rowXStart) / itemWidth).toInt()

        if (r >= _hourCount || c >= 6) {
            Log.e(
                "area",
                "area error r:$r, c:$c, touchY:$touchY, touchX:$touchX, itemHeight:$itemHeight, itemWidth:$itemWidth, height:$height, width:$width"
            )
        }

        if (r >= 23) {
            r = 23
        }

        if (c >= 6) {
            c = 6
        }

        return Pair(r, c)
    }

    fun dp2px(dpValue: Float): Int {
        return (0.5f + dpValue * Resources.getSystem().displayMetrics.density).toInt()
    }
}